--
-- CSSE2000 8 Bit Microprocessor
-- Copyright (C) 2011 Nathan Rossi (University of Queensland)
--
-- THIS DESIGN/CODE IS PROVIDED TO YOU UNDER THE FOLLOWING LICENSE:
--
-- All material is restricted to use in the CSSE2000 Project for 2011.
-- You may not redistribute the file/code/design, without the consent of the author.
--
-- DO NOT MODIFY THIS FILE
--

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

library work;
use work.proc_package.ALL;
use work.proc_components.ALL;

entity proc_top is
	port (
		-- Control
		clk : in std_logic;
		rst : in std_logic;
		en : in std_logic;
		
		halt : in std_logic;
		
		-- Debug Port
		debug_reg_addr : in PROC_REG_ADDR_TYPE;
		debug_reg_wr_en : in std_logic;
		debug_reg_in : in PROC_REG_DATA_TYPE;
		debug_reg_out : out PROC_REG_DATA_TYPE;
		debug_pc_out : out PROC_PROG_ADDR_TYPE;
		debug_instruction : out PROC_PROG_DATA_TYPE;
		
		-- External Bus
		bus_out : in PROC_BUS_DATA_TYPE;
		bus_in : out PROC_BUS_DATA_TYPE;
		bus_addr : out PROC_BUS_ADDR_TYPE;
		bus_busy : in std_logic;
		bus_rdwr : out std_logic;
		bus_en : out std_logic;
		bus_rst : out std_logic;
		bus_clk : out std_logic;
		
		-- External Program Memory (For Instruction Fetcher)
		prog_mem_clk : out std_logic;
		prog_mem_en : out std_logic;
		prog_mem_addr : out PROC_PROG_ADDR_TYPE;
		prog_mem_data : in PROC_PROG_DATA_TYPE
	);
end proc_top;

architecture Behavioral of proc_top is
	signal immediate : PROC_REG_DATA_TYPE;

	-- Instruction Fetcher Signals
	signal if_value : PROC_PROG_DATA_TYPE;

	-- Control Logic Signals
	signal cu_immediate : PROC_REG_DATA_TYPE;
	signal cu_rf_p_0_addr_direct : PROC_REG_ADDR_TYPE;
	signal cu_rf_p_0_wr_en : std_logic;
	signal cu_rf_en : std_logic;
	signal cu_en : std_logic;

	-- Register File Signals
	signal rf_en : std_logic;
	signal rf_p_0_wr_en : std_logic;
	signal rf_p_0_write_source : PROC_MUX_SOURCE;
	signal rf_p_0_addr_direct : PROC_REG_ADDR_TYPE;
	signal rf_p_0_datain : PROC_REG_DATA_TYPE;
	signal rf_p_0_dataout : PROC_REG_DATA_TYPE;
	signal rf_p_1_addr_direct : PROC_REG_ADDR_TYPE;
	signal rf_p_1_dataout : PROC_REG_DATA_TYPE;

	-- ALU Signals
	signal alu_en : std_logic;
	signal alu_b_source : PROC_MUX_SOURCE;
	signal alu_mode : PROC_ALU_MODE;
	signal alu_status_out : PROC_REG_DATA_TYPE;
	signal alu_b : PROC_REG_DATA_TYPE;
    signal alu_result : PROC_REG_DATA_TYPE;

	-- Program Counter Signals
	signal pc_en : std_logic;
	signal pc_jump_source : PROC_MUX_SOURCE;
	signal pc_mode : PROC_PC_MODE;
	signal pc_value_in : PROC_PROG_ADDR_TYPE;
	signal pc_value_out : PROC_PROG_ADDR_TYPE;
	signal pc_en_gen : std_logic;

	-- Status Register Signals
	signal sreg_en : std_logic;
	signal sreg_value_in : PROC_REG_DATA_TYPE;
	signal sreg_value_out : PROC_REG_DATA_TYPE;
	signal sreg_source : PROC_MUX_SOURCE;

	-- Status Register Bit Manipulator Signals
	signal sreg_bit_en : std_logic;
	signal sreg_bit_value_in : PROC_REG_DATA_TYPE;
	signal sreg_bit_index : PROC_REG_BIT_INDEX_TYPE;
	signal sreg_bit_in : std_logic;
	signal sreg_bit_eq : std_logic;
	signal sreg_jump_en : std_logic;
	
	-- Memory Controller Signals
	signal mem_en : std_logic;
	signal mem_addr_source : PROC_MUX_SOURCE;

begin

	-- Instruction Fetcher (Has Access to the External Memory Port)
	inf: proc_instructionfetcher port map (
		clk => clk,
		en => en,
		addr => pc_value_out,
		value => if_value,
		
		prog_mem_clk => prog_mem_clk,
		prog_mem_en => prog_mem_en,
		prog_mem_addr => prog_mem_addr,
		prog_mem_data => prog_mem_data
	);

	-- Debug Interface
	debug_instruction <= if_value; -- Output Instruction Value
	debug_pc_out <= pc_value_out; -- Output Program Counter Value
	debug_reg_out <= rf_p_0_dataout; -- Output Register File Port 0 Value
	
	-- Immediate Value MUX (for debug/control unit switching)
	immediate <= debug_reg_in when (halt = '1') else
				 cu_immediate;
	-- Register Address MUX (for debug/control unit switching)
	rf_p_0_addr_direct <= debug_reg_addr when (halt = '1') else
						  cu_rf_p_0_addr_direct;
	-- Register Write Enable MUX (for debug/control unit switching)
	rf_p_0_wr_en <= debug_reg_wr_en when (halt = '1') else
					cu_rf_p_0_wr_en;
	-- Register Enable MUX (for debug/control unit switching)
	rf_en <= '1' when (halt = '1') else
			 cu_rf_en;

	-- Control Unit Enable Logic
	cu_en <= not (halt) and en;
	
	-- Control Unit
	cu: proc_controlunit port map (
		clk => clk,
		rst => rst,
		en => cu_en,
		
		instruction => if_value,
		immediate_value => cu_immediate,
		
		register_en => cu_rf_en,
		register_p_0_write => cu_rf_p_0_wr_en,
		register_p_0_write_source => rf_p_0_write_source,
		register_p_0_addr_direct => cu_rf_p_0_addr_direct,
		register_p_1_addr_direct => rf_p_1_addr_direct,
		
		alu_en => alu_en,
		alu_b_source => alu_b_source,
		alu_mode => alu_mode,
		
		pc_en => pc_en,
		pc_jump_source => pc_jump_source,
		pc_mode => pc_mode,
		
		sreg_en => sreg_en,
		sreg_source => sreg_source,
		
		sreg_bit_en => sreg_bit_en,
		sreg_bit_index => sreg_bit_index,
		sreg_bit_value_in => sreg_bit_in,
		sreg_jump_en => sreg_jump_en,
		
		mem_en => mem_en,
		mem_addr_source => mem_addr_source
	);

	-- Branch Program Counter Jump Enable Generator
	process (sreg_jump_en, sreg_bit_eq, pc_en)
	begin
		if (sreg_jump_en = '1') then
			if (sreg_bit_eq = '1') then
				pc_en_gen <= pc_en;
			else
				pc_en_gen <= '0';
			end if;
		else
			pc_en_gen <= pc_en;
		end if;
	end process;
	
	-- Program Counter Input MUX
	pc_value_in <= rf_p_0_dataout when (pc_jump_source = SRC_REGISTER_P_0) else immediate;
	-- Program COunter
	pc: proc_progcounter port map (
		clk => clk,
		rst => rst,
		en => pc_en_gen,
		mode => pc_mode,
		value_in => pc_value_in,
		value_out => pc_value_out
	);
	
	-- Register Input MUX
	rf_p_0_datain <= rf_p_1_dataout when (rf_p_0_write_source = SRC_REGISTER_P_1) else
					 alu_result when (rf_p_0_write_source = SRC_ALU_RESULT) else
					 immediate;
	-- Register File
	rf: proc_registers port map (
		clk => clk,
		rst => rst,
		en => rf_en,
		p_0_wr_en => rf_p_0_wr_en,
		p_0_addr => rf_p_0_addr_direct,
		p_1_addr => rf_p_1_addr_direct,
		p_0_datain => rf_p_0_datain,
		p_0_dataout => rf_p_0_dataout,
		p_1_dataout => rf_p_1_dataout
	);
	
	-- ALU B Input MUX
	alu_b <= rf_p_1_dataout when (alu_b_source = SRC_REGISTER_P_1) else immediate;
	-- ALU
	alu: proc_alu port map (
		clk => clk,
		rst => rst,
		en => alu_en,
		mode => alu_mode,
		status_in => sreg_value_out,
		a => rf_p_0_dataout,
		b => alu_b,
		result => alu_result,
		status_out => alu_status_out
	);
	
	-- Status Register MUX
	sreg_value_in <= sreg_bit_value_in when (sreg_source = SRC_SREG_BITSET) else alu_status_out;
	-- Status Register
	sreg: proc_sreg port map (
		rst => rst,
		clk => clk,
		en => sreg_en,
		input => sreg_value_in,
		output => sreg_value_out
	);

	-- Status Register Bit Manipulator
	sreg_bm : proc_bitmanipulator port map (
		rst => rst,
		clk => clk,
		en => sreg_bit_en,
		value_in => sreg_value_out,
		value_out => sreg_bit_value_in,
		bit_index => sreg_bit_index,
		bit_in => sreg_bit_in,
		bit_eq => sreg_bit_eq
	);
end Behavioral;

